package com.miniapp.controller;

import com.miniapp.entity.BaseFile;
import com.miniapp.entity.BusinessFile;
import com.miniapp.entity.R;
import com.miniapp.service.BaseFileService;
import com.miniapp.service.BusinessFileService;
import com.miniapp.service.FileStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * 文件管理公共接口控制器
 *
 * <p>提供文件上传、下载、业务绑定及临时文件管理等公共接口
 *
 * @author yourName
 * @date 2025-09-06
 */
@RestController
@RequestMapping("/api/files")
@Api(tags = "文件管理公共接口")
public class FileController {

    @Autowired
    private BaseFileService baseFileService;

    @Autowired
    private BusinessFileService businessFileService;

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 通用文件上传接口
     *
     * @param file 上传的文件
     * @param isTemporary 是否为临时文件
     * @param dir 存储目录（可选）
     * @return 包含文件信息的响应
     */
    @PostMapping("/upload")
    @ApiOperation(value = "通用文件上传", notes = "上传文件并返回文件信息，支持临时/正式文件标记")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "上传的文件", required = true, dataType = "java.io.File"),
            @ApiImplicitParam(name = "isTemporary", value = "是否为临时文件（true/false）",
                    required = true, dataType = "boolean", defaultValue = "false"),
            @ApiImplicitParam(name = "dir", value = "存储目录（可选，为空时自动生成）",
                    dataType = "String")
    })
    public R<BaseFile> uploadFile(@RequestPart @RequestParam("file") MultipartFile file,
                                  @RequestParam(defaultValue = "1") boolean isTemporary,
                                  @RequestParam(required = false) String dir) {
        BaseFile baseFile = baseFileService.uploadFile(file, isTemporary, dir);
        return R.success(baseFile);
    }

    /**
     * 文件下载接口
     *
     * @param fileId 文件ID
     * @param response 响应对象
     */
    @GetMapping("/download/{fileId}")
    @ApiOperation(value = "文件下载", notes = "根据文件ID下载文件")
    @ApiImplicitParam(name = "fileId", value = "文件ID", required = true,
            dataType = "Long", paramType = "path")
    public void downloadFile(@PathVariable Long fileId, HttpServletResponse response) {
        try (InputStream is = baseFileService.getFileInputStream(fileId);
             OutputStream os = response.getOutputStream()) {

            // 获取文件信息
            BaseFile baseFile = baseFileService.getById(fileId);
            if (baseFile == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
                return;
            }

            // 设置响应头
            response.setContentType(baseFile.getFileType());
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(baseFile.getFileName(), "UTF-8"));
            response.setContentLengthLong(baseFile.getFileSize());

            // 写入响应流
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            throw new RuntimeException("文件下载失败: " + e.getMessage());
        }
    }

    /**
     * 将临时文件转换为正式文件并绑定业务
     *
     * @param fileId 临时文件ID
     * @param businessCode 业务编码
     * @param businessType 业务类型
     * @param sort 排序号
     * @return 业务文件关联信息
     */
    @PostMapping("/bind/{fileId}")
    @ApiOperation(value = "绑定临时文件到业务", notes = "将临时文件转换为正式文件并与业务关联")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileId", value = "临时文件ID", required = true,
                    dataType = "Long", paramType = "path"),
            @ApiImplicitParam(name = "businessCode", value = "业务编码", required = true,
                    dataType = "String"),
            @ApiImplicitParam(name = "businessType", value = "业务类型", required = true,
                    dataType = "String"),
            @ApiImplicitParam(name = "sort", value = "排序号（可选）", dataType = "Integer")
    })
    public R<BusinessFile> bindTempFileToBusiness(@PathVariable Long fileId,
                                                  @RequestParam String businessCode,
                                                  @RequestParam String businessType,
                                                  @RequestParam(required = false) Integer sort) {
        // 1. 将临时文件转换为正式文件
        BaseFile formalFile = baseFileService.convertToFormalFile(fileId, businessType, businessCode);

        // 2. 绑定到业务
        BusinessFile businessFile = new BusinessFile();
        businessFile.setBaseFileId(formalFile.getId());
        businessFile.setBusinessCode(businessCode);
        businessFile.setBusinessType(businessType);
        businessFile.setSort(sort != null ? sort : 0);
        businessFile.setCreateTime(java.time.LocalDateTime.now());

        businessFileService.save(businessFile);
        return R.success(businessFile);
    }

    /**
     * 上传并直接绑定业务文件
     *
     * @param file 上传的文件
     * @param businessCode 业务编码
     * @param businessType 业务类型
     * @param sort 排序号
     * @return 业务文件关联信息
     */
    @PostMapping("/upload-and-bind")
    @ApiOperation(value = "上传并绑定业务文件", notes = "上传文件并直接与业务建立关联（直接作为正式文件）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "上传的文件", required = true, dataType = "__file"),
            @ApiImplicitParam(name = "businessCode", value = "业务编码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "businessType", value = "业务类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "sort", value = "排序号（可选）", dataType = "Integer")
    })
    public R<BusinessFile> uploadAndBind(@RequestParam("file") MultipartFile file,
                                         @RequestParam String businessCode,
                                         @RequestParam String businessType,
                                         @RequestParam(required = false) Integer sort) {
        // 1. 上传为正式文件，目录格式：业务类型/业务编码
        String dir = businessType + "/" + businessCode;
        BaseFile baseFile = baseFileService.uploadFile(file, false, dir);

        // 2. 绑定到业务
        BusinessFile businessFile = new BusinessFile();
        businessFile.setBaseFileId(baseFile.getId());
        businessFile.setBusinessCode(businessCode);
        businessFile.setBusinessType(businessType);
        businessFile.setSort(sort != null ? sort : 0);
        businessFile.setCreateTime(java.time.LocalDateTime.now());

        businessFileService.save(businessFile);
        return R.success(businessFile);
    }

    /**
     * 根据业务查询文件列表
     *
     * @param businessCode 业务编码
     * @param businessType 业务类型
     * @return 业务关联的文件列表
     */
    @GetMapping("/business")
    @ApiOperation(value = "查询业务关联文件", notes = "根据业务编码和类型查询关联的文件列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessCode", value = "业务编码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "businessType", value = "业务类型", required = true, dataType = "String")
    })
    public R<List<BusinessFile>> getFilesByBusiness(@RequestParam String businessCode,
                                                    @RequestParam String businessType) {
        List<BusinessFile> files = businessFileService.getByBusiness(businessCode, businessType);
        return R.success(files);
    }

    /**
     * 删除文件
     *
     * @param fileId 文件ID
     * @return 操作结果
     */
    @DeleteMapping("/{fileId}")
    @ApiOperation(value = "删除文件", notes = "删除文件(同时解除所有业务关联)")
    @ApiImplicitParam(name = "fileId", value = "文件ID", required = true,
            dataType = "Long", paramType = "path")
    public R<Boolean> deleteFile(@PathVariable Long fileId) {
        boolean result = baseFileService.deleteFile(fileId);
        return R.success(result);
    }

    /**
     * 手动清理过期临时文件（测试用）
     *
     * @return 清理的文件数量
     */
    @PostMapping("/clean-temp-files")
    @ApiOperation(value = "清理过期临时文件", notes = "手动触发清理过期临时文件（生产环境建议依赖定时任务）")
    public R<Integer> cleanExpiredTemporaryFiles() {
        int count = baseFileService.cleanExpiredTemporaryFiles();
        return R.success(count);
    }

    /**
     * 根据文件ID获取临时访问链接
     *
     * @param fileId 文件ID
     * @return 带签名的临时访问URL
     */
    @GetMapping("/temporary-url/{fileId}")
    @ApiOperation("获取文件临时访问链接（默认30分钟）")
    public R<String> getTemporaryUrl(@PathVariable Long fileId) {
        BaseFile baseFile = baseFileService.getById(fileId);
        if (baseFile == null) {
            return R.error("文件不存在");
        }
        String temporaryUrl = fileStorageService.generateTemporaryUrl(baseFile.getFileKey(), baseFile.getFileType(),
                baseFile.getFileName());
        return R.success(temporaryUrl);
    }
}
    